﻿ using System;
using System.Collections.Generic;
using System.Linq;
using System.ComponentModel;
using System.Collections;
using System.Threading;

using BEX.Core.Exchange;
using BEX.Core.Exchange.BTCE;
using BEX.Core.Exchange.MtGox;
using BEX.Core.Exchange.Coinbase;
using BEX.Core.Exchange.BITSTAMP;
using BEX.Core.Exchange.BITFINEX;
using BEX.Core.Exchange.TRADEHILL;
using BEX.Core.Exchange.CAMPBX;

using BEX.DataAccess;

using BEX.Core;

namespace BEX
{
    public class ExchangeMonitor
    {
        private MtGox _gox = new MtGox();
        private BTCE _btce = new BTCE();
        private Coinbase _coinbase = new Coinbase();
        private Bitstamp _bitstamp = new Bitstamp();
        private Bitfinex _bitfinex = new Bitfinex();
        private Tradehill _tradeh = new Tradehill();
        private CampBX _campbx = new CampBX();
        protected List<CurrencyPair> _toListen = new List<CurrencyPair>();

        protected Thread[] _workers = new Thread[7];
        //protected System.ComponentModel.BackgroundWorker[] _watchers = new BackgroundWorker[7];
        
        public bool MonitorCampBX { get; set; }

        public bool MonitorTradehill { get; set; }

        public bool MonitorBitFinex { get; set; }

        public bool MonitorBitstamp { get; set; }

        public bool MonitorCoinbase { get; set; }

        public bool MonitorGox { get; set; }

        public bool MonitorBTCE { get; set; }

        public ExchangeMonitor()
        {
        }

        public void AddMonitoredCurrency(CurrencyPair to_watch)
        {
            _toListen.Add(to_watch);
        }

        public void Listen()
        {
            _gox = (MtGox)ExchangeDAL.GetByID((int)ExchangeType.MTGOX);

            foreach (CurrencyPair _t in _toListen)
            {
               // _gox.AddMonitoredCurrency(_t);
            }
            //_gox.OnUpdateStatus += _gox_OnUpdateStatus;

            _workers[0] = new Thread(mtGox_DoWork);
         
            _btce = (BTCE)ExchangeDAL.GetByID((int)ExchangeType.BTCE);

            foreach (CurrencyPair _t in _toListen)
            {
                //_btce.AddMonitoredCurrency(_t);
            }
            //_btce.OnUpdateStatus += _gox_OnUpdateStatus;

            _workers[1] = new Thread(btce_DoWork);
  
            _coinbase = (Coinbase)ExchangeDAL.GetByID((int)ExchangeType.COINBASE);

            foreach (CurrencyPair _t in _toListen)
            {
                //_coinbase.AddMonitoredCurrency(_t);
            }

           //_coinbase.OnUpdateStatus += _gox_OnUpdateStatus;

            _workers[2] = new Thread(coinbase_DoWork);
            

            _bitstamp = (Bitstamp)ExchangeDAL.GetByID((int)ExchangeType.BITSTAMP);

            foreach (CurrencyPair _t in _toListen)
            {
               // _bitstamp.AddMonitoredCurrency(_t);
            }

            //_bitstamp.OnUpdateStatus += _gox_OnUpdateStatus;

            _workers[3] = new Thread(Bitstamp_DoWork);
         


            _bitfinex = (Bitfinex)ExchangeDAL.GetByID((int)ExchangeType.BITFINEX);

            foreach (CurrencyPair _t in _toListen)
            {
               // _bitfinex.AddMonitoredCurrency(_t);
            }

            //_bitfinex.OnUpdateStatus += _gox_OnUpdateStatus;

            _workers[4] = new Thread(Bitfinex_DoWork);
            


            _tradeh = (Tradehill)ExchangeDAL.GetByID((int)ExchangeType.TRADEHILL);

            foreach (CurrencyPair _t in _toListen)
            {
                //_tradeh.AddMonitoredCurrency(_t);
            }

            //_tradeh.OnUpdateStatus += _gox_OnUpdateStatus;

            _workers[5] = new Thread(Tradehill_DoWork);
   

            _campbx = (CampBX)ExchangeDAL.GetByID((int)ExchangeType.CAMPBX);

            foreach (CurrencyPair _t in _toListen)
            {
               // _campbx.AddMonitoredCurrency(_t);
            }

           // _campbx.OnUpdateStatus += _gox_OnUpdateStatus;

            _workers[6] = new Thread(CampBX_DoWork);
            


            if (MonitorGox)
            {
                _workers[0].Start();
            }
            if (MonitorBTCE)
            {
                _workers[1].Start();
            }
            if (MonitorCoinbase)
            {
                _workers[2].Start();
            }
            if (MonitorBitstamp)
            {
                _workers[3].Start();
            }
            if (MonitorBitFinex)
            {
                _workers[4].Start();
            }
            if (MonitorTradehill)
            {
                _workers[5].Start();
            }
            if (MonitorCampBX)
            {
                _workers[6].Start();
            }
        }

        protected void ProcessTick(Tick t)
        {
            Tick current = TickDAL.GetCurrentTick(t.ExchangeSource, t.Currency);

            if (null == current)
            {
                TickDAL.Save(t);
                InvokeStatusEvent("Saving Initial Tick " + t.Currency.Base.ToString() + "/" + t.Currency.Counter.ToString() + " - Bid: " + t.Bid.ToString() + " - Ask: " + t.Ask.ToString(), t.ExchangeSource);

            }
            else if (t.Currency == current.Currency && t.ExchangeSource == current.ExchangeSource)
            {

                if (t.ExchangeSource == ExchangeType.COINBASE)
                {
                    if (t.Spot != current.Spot)
                    {
                        TickDAL.Save(t);
                        InvokeStatusEvent("Saving Tick " + t.Currency.Base.ToString() + "/" + t.Currency.Counter.ToString() + " - Spot: " + t.Spot.ToString(), t.ExchangeSource);

                    }
                }
                else if (current.Ask != t.Ask
                    || current.Bid != t.Bid
                   )
                {

                    TickDAL.Save(t);

                    InvokeStatusEvent("Saving Tick " + t.Currency.Base.ToString() + "/" + t.Currency.Counter.ToString() + " - Bid: " + t.Bid.ToString() + " - Ask: " + t.Ask.ToString(), t.ExchangeSource);

                }

            }

        }

        protected void ProcessSpot(Tick t)
        {
            Tick current = TickDAL.GetCurrentTick(t.ExchangeSource, t.Currency);

            if (null == current)
            {
                TickDAL.Save(t);
                InvokeStatusEvent("Saving Initial Tick " + t.Currency.Base.ToString() + "/" + t.Currency.Counter.ToString() + " - Spot: " + t.Spot.ToString(), t.ExchangeSource);

            }
            else if (t.Currency == current.Currency && t.ExchangeSource == current.ExchangeSource)
            {
                if (current.Spot != t.Spot)
                {

                    TickDAL.Save(t);

                    InvokeStatusEvent("Saving Tick " + t.Currency.Base.ToString() + "/" + t.Currency.Counter.ToString() + " - Spot: " + t.Spot.ToString(), t.ExchangeSource);

                }

            }

        }

        protected void CampBX_DoWork()
        {

            InvokeStatusEvent("Monitoring " + ExchangeType.CAMPBX.ToString(), ExchangeType.CAMPBX);
            List<CurrencyPair> _finalPairs = _toListen.Intersect(_campbx.SupportedPairs).ToList();

            while (true)
            {

                foreach (CurrencyPair _p in _finalPairs)
                {
                    ProcessTick(_campbx.GetTick(_p));
                    Thread.Sleep(2000);
                }
            }
 
        }

        protected void Tradehill_DoWork()
        {
            InvokeStatusEvent("Monitoring " + ExchangeType.TRADEHILL.ToString(), ExchangeType.TRADEHILL);



            List<CurrencyPair> _finalPairs = _toListen.Intersect(_tradeh.SupportedPairs).ToList();

            while (true)
            {

                foreach (CurrencyPair _p in _finalPairs)
                {
                    ProcessTick(_tradeh.GetTick(_p));
                    Thread.Sleep(2000);
                }
            }
        }

        protected void Bitfinex_DoWork()
        {
            InvokeStatusEvent("Monitoring " + ExchangeType.BITFINEX.ToString(), ExchangeType.BITFINEX);

            List<CurrencyPair> _finalPairs = _toListen.Intersect(_bitfinex.SupportedPairs).ToList();

            while (true)
            {

                foreach (CurrencyPair _p in _finalPairs)
                {
                    ProcessTick(_bitfinex.GetTick(_p));
                    Thread.Sleep(2000);
                }
            }
 

        }

        protected void coinbase_DoWork()
        {
            InvokeStatusEvent("Monitoring " + ExchangeType.COINBASE.ToString(), ExchangeType.COINBASE);

            List<CurrencyPair> _finalPairs = _toListen.Intersect(_coinbase.SupportedPairs).ToList();

            while (true)
            {

                foreach (CurrencyPair _p in _finalPairs)
                {
                    ProcessTick(_coinbase.GetTick(_p));
                    Thread.Sleep(2000);
                }
            }
        }

        protected void Bitstamp_DoWork()
        {
            // _bitstamp.Listen();

            InvokeStatusEvent("Monitoring " + ExchangeType.BITSTAMP.ToString(), ExchangeType.BITSTAMP);

            List<CurrencyPair> _finalPairs = _toListen.Intersect(_bitstamp.SupportedPairs).ToList();

            while (true)
            {

                foreach (CurrencyPair _p in _finalPairs)
                {
                    ProcessTick(_bitstamp.GetTick(_p));
                    Thread.Sleep(2000);
                }
            }
 
        }

        protected void btce_DoWork()
        {

            InvokeStatusEvent("Monitoring " + ExchangeType.BTCE.ToString(), ExchangeType.BTCE);


            List<CurrencyPair> _finalPairs = _toListen.Intersect(_btce.SupportedPairs).ToList();

            while (true)
            {

                foreach (CurrencyPair _p in _finalPairs)
                {
                    ProcessTick(_btce.GetTick(_p));
                    Thread.Sleep(2000);
                }
            }
        }

        protected void mtGox_DoWork()
        {

            InvokeStatusEvent("Monitoring " + ExchangeType.MTGOX.ToString(), ExchangeType.MTGOX);

            List<CurrencyPair> _finalPairs = _toListen.Intersect(_gox.SupportedPairs).ToList();

            while (true)
            {

                foreach (CurrencyPair _p in _finalPairs)
                {
                    ProcessTick(_gox.GetTick(_p));
                    Thread.Sleep(2000);
                }
            }
        }

        protected void _gox_OnUpdateStatus(object sender, ProgressEventArgs e)
        {
            InvokeStatusEvent(e.Status, e.Exchange);
        }

        protected void InvokeStatusEvent(string status, ExchangeType exch)
        {
            if (OnUpdateStatus == null)
            {
                return;
            }
            var args = new ProgressEventArgs(status, exch);

            OnUpdateStatus.Raise(null, args);
        }

        public delegate void StatusUpdateHandler(object sender, ProgressEventArgs e);

        public event StatusUpdateHandler OnUpdateStatus;
    }
}
